using System;
using System.Collections.Generic;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using WsdTestService.Discovery;
using WsdTestService.Metadata;

namespace WsdTestService
{
    /// <summary>
    /// WSD测试服务程序
    /// 用于验证Windows"添加设备"能否发现WSD打印机
    /// </summary>
    class Program
    {
        private static WsdDiscoveryService _discoveryService;
        private static WsdMetadataService _metadataService;
        private static HttpListener _httpListener;
        private static CancellationTokenSource _cancellationTokenSource;

        static void Main(string[] args)
        {
            Console.WriteLine("==========================================");
            Console.WriteLine("WSD 测试服务程序");
            Console.WriteLine("用于验证Windows能否发现WSD打印机");
            Console.WriteLine("==========================================");
            Console.WriteLine();

            _cancellationTokenSource = new CancellationTokenSource();

            try
            {
                // 获取本机IP地址（优先使用局域网IP）
                var localIp = GetLocalIpAddress();
                var port = 8080; // HTTP Metadata端点端口

                Console.WriteLine($"检测到的IP地址列表：");
                try
                {
                    var hostEntry = Dns.GetHostEntry(Dns.GetHostName());
                    foreach (var ip in hostEntry.AddressList)
                    {
                        if (ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork &&
                            !IPAddress.IsLoopback(ip))
                        {
                            var ipString = ip.ToString();
                            var isSelected = ipString == localIp ? " ← 已选择（局域网IP）" : "";
                            Console.WriteLine($"  • {ipString}{isSelected}");
                        }
                    }
                }
                catch { }
                Console.WriteLine();
                Console.WriteLine($"使用的IP地址: {localIp}");
                Console.WriteLine($"HTTP端口: {port}");
                Console.WriteLine();

                // 确保防火墙规则已添加
                EnsureFirewallRules(localIp, port);

                // 确保 HTTP URL 预留已注册（Windows 要求）
                // 同时为所有网卡（+）和特定IP注册URL预留
                EnsureHttpUrlReservation(localIp, port);
                EnsureHttpUrlReservation("+", port);

                // 设备信息（模拟打印机）
                var deviceUuid = "550e8400-e29b-41d4-a716-446655440000"; // 测试用的固定UUID
                var printerName = "测试IPP打印机";
                var printerUri = $"http://{localIp}:{port}/ipp/printers/test-printer";

                Console.WriteLine($"设备UUID: {deviceUuid}");
                Console.WriteLine($"打印机名称: {printerName}");
                Console.WriteLine($"打印机URI: {printerUri}");
                Console.WriteLine();

                // 1. 启动WSD发现服务（UDP 3702）
                Console.WriteLine("正在启动WSD发现服务（UDP 3702）...");
                _discoveryService = new WsdDiscoveryService(deviceUuid, printerName, localIp, port, printerUri);
                if (_discoveryService.Start())
                {
                    Console.WriteLine("✓ WSD发现服务已启动");
                }
                else
                {
                    Console.WriteLine("✗ WSD发现服务启动失败");
                    return;
                }
                Console.WriteLine();

                // 2. 启动HTTP Metadata服务
                Console.WriteLine("正在启动HTTP Metadata服务...");
                _metadataService = new WsdMetadataService(deviceUuid, printerName, localIp, port, printerUri);
                _httpListener = new HttpListener();
                
                // 监听所有网卡（使用+通配符），确保客户端可以从任何网卡访问
                // localhost 不需要 URL 预留，+ 需要 URL 预留或管理员权限
                bool localhostAdded = false;
                bool allInterfacesAdded = false;
                
                // 先添加 localhost（不需要权限）
                try
                {
                    _httpListener.Prefixes.Add($"http://localhost:{port}/");
                    _httpListener.Prefixes.Add($"http://127.0.0.1:{port}/");
                    localhostAdded = true;
                    Console.WriteLine($"  ✓ 已添加 localhost 监听");
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"  ⚠ 添加 localhost 监听失败: {ex.Message}");
                }
                
                // 添加所有网卡监听（使用+通配符，监听所有IP地址）
                try
                {
                    _httpListener.Prefixes.Add($"http://+:{port}/");
                    allInterfacesAdded = true;
                    Console.WriteLine($"  ✓ 已添加所有网卡监听: *:{port}");
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"  ⚠ 添加所有网卡监听失败: {ex.Message}");
                    // 如果+失败，尝试添加特定IP地址
                    try
                    {
                _httpListener.Prefixes.Add($"http://{localIp}:{port}/");
                        allInterfacesAdded = true;
                        Console.WriteLine($"  ✓ 已添加 IP 地址监听: {localIp}:{port}");
                    }
                    catch (Exception ex2)
                    {
                        Console.WriteLine($"  ⚠ 添加 IP 地址监听也失败: {ex2.Message}");
                        Console.WriteLine($"  提示：请确保已注册 URL 预留或以管理员身份运行");
                        Console.WriteLine($"  手动注册命令: netsh http add urlacl url=http://+:{port}/ user=Everyone");
                    }
                }
                
                // 启动 HTTP 监听器
                try
                {
                    if (!localhostAdded && !allInterfacesAdded)
                    {
                        throw new InvalidOperationException("无法添加任何 HTTP 前缀");
                    }
                    
                _httpListener.Start();
                    if (localhostAdded && allInterfacesAdded)
                    {
                        Console.WriteLine($"✓ HTTP Metadata服务已启动（端口 {port}，监听所有网卡）");
                    }
                    else if (localhostAdded)
                    {
                        Console.WriteLine($"✓ HTTP Metadata服务已启动（端口 {port}，仅监听 localhost）");
                        Console.WriteLine($"  ⚠ 警告：客户端无法访问，因为所有网卡监听未添加");
                        Console.WriteLine($"  请以管理员身份运行，或手动注册 URL 预留：");
                        Console.WriteLine($"  netsh http add urlacl url=http://+:{port}/ user=Everyone");
                    }
                    else if (allInterfacesAdded)
                    {
                        Console.WriteLine($"✓ HTTP Metadata服务已启动（端口 {port}，监听所有网卡）");
                    }
                    else
                    {
                Console.WriteLine($"✓ HTTP Metadata服务已启动（端口 {port}）");
                    }
                    Console.WriteLine();
                }
                catch (System.Net.HttpListenerException ex) when (ex.ErrorCode == 5)
                {
                    Console.WriteLine($"✗ HTTP Metadata服务启动失败：拒绝访问");
                    Console.WriteLine();
                    Console.WriteLine("解决方案：");
                    Console.WriteLine("  1. 以管理员身份运行此程序");
                    Console.WriteLine($"  2. 或者手动注册 URL 预留（以管理员身份运行）：");
                    Console.WriteLine($"     netsh http add urlacl url=http://{localIp}:{port}/ user=Everyone");
                Console.WriteLine();
                    throw;
                }

                // 3. 启动HTTP监听循环
                var httpTask = Task.Run(() => HttpListenerLoop(_httpListener, _cancellationTokenSource.Token));
                Console.WriteLine("✓ HTTP请求监听已启动");
                Console.WriteLine();

                Console.WriteLine("==========================================");
                Console.WriteLine("服务运行中...");
                Console.WriteLine($"请在Windows客户端打开'添加设备'，查看是否能发现：'{printerName}'");
                Console.WriteLine("按 Ctrl+C 停止服务");
                Console.WriteLine("==========================================");
                Console.WriteLine();

                // 4. 发送Hello消息（设备上线公告）
                // 注意：Hello消息会在启动后1秒自动发送，然后每30秒定期发送
                // 这里手动发送一次以确保立即宣告设备存在
                Console.WriteLine("正在发送WSD Hello消息（设备上线公告）...");
                _discoveryService.SendHello();
                Console.WriteLine("✓ Hello消息已发送（后续将每30秒自动发送）");
                Console.WriteLine();

                // 等待退出信号
                Console.CancelKeyPress += (sender, e) =>
                {
                    e.Cancel = true;
                    _cancellationTokenSource.Cancel();
                    Console.WriteLine();
                    Console.WriteLine("正在停止服务...");
                };

                // 保持运行
                _cancellationTokenSource.Token.WaitHandle.WaitOne();
            }
            catch (Exception ex)
            {
                Console.WriteLine($"错误: {ex.Message}");
                Console.WriteLine($"堆栈跟踪: {ex.StackTrace}");
            }
            finally
            {
                Cleanup();
            }
        }

        private static async Task HttpListenerLoop(HttpListener listener, CancellationToken cancellationToken)
        {
            while (!cancellationToken.IsCancellationRequested)
            {
                try
                {
                    var context = await listener.GetContextAsync().ConfigureAwait(false);
                    _ = Task.Run(async () =>
                    {
                        try
                        {
                            await _metadataService.HandleRequestAsync(context.Request, context.Response).ConfigureAwait(false);
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine($"处理HTTP请求时发生错误: {ex.Message}");
                        }
                    }, cancellationToken);
                }
                catch (HttpListenerException ex) when (ex.ErrorCode == 995)
                {
                    // 正常关闭
                    break;
                }
                catch (ObjectDisposedException)
                {
                    // 正常关闭
                    break;
                }
                catch (Exception ex)
                {
                    if (!cancellationToken.IsCancellationRequested)
                    {
                        Console.WriteLine($"HTTP监听错误: {ex.Message}");
                    }
                }
            }
        }

        private static string GetLocalIpAddress()
        {
            try
            {
                var hostEntry = Dns.GetHostEntry(Dns.GetHostName());
                var localIps = new List<IPAddress>();
                
                foreach (var ip in hostEntry.AddressList)
                {
                    if (ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork &&
                        !IPAddress.IsLoopback(ip))
                    {
                        localIps.Add(ip);
                    }
                }
                
                // 优先选择192.168.1.x网段（最常见的局域网网段）
                foreach (var ip in localIps)
                {
                    var ipBytes = ip.GetAddressBytes();
                    if (ipBytes[0] == 192 && ipBytes[1] == 168 && ipBytes[2] == 1)
                    {
                        return ip.ToString();
                    }
                }
                
                // 其次选择其他192.168.x.x网段
                foreach (var ip in localIps)
                {
                    var ipBytes = ip.GetAddressBytes();
                    if (ipBytes[0] == 192 && ipBytes[1] == 168)
                    {
                        return ip.ToString();
                    }
                }
                
                // 然后选择10.x.x.x
                foreach (var ip in localIps)
                {
                    var ipBytes = ip.GetAddressBytes();
                    if (ipBytes[0] == 10)
                    {
                        return ip.ToString();
                    }
                }
                
                // 最后选择172.16.x.x - 172.31.x.x
                foreach (var ip in localIps)
                {
                    var ipBytes = ip.GetAddressBytes();
                    if (ipBytes[0] == 172 && ipBytes[1] >= 16 && ipBytes[1] <= 31)
                    {
                        return ip.ToString();
                    }
                }
                
                // 如果没有找到局域网IP，返回第一个非回环IP
                if (localIps.Count > 0)
                {
                    return localIps[0].ToString();
                }
                
                return "127.0.0.1";
            }
            catch
            {
                return "127.0.0.1";
            }
        }

        private static void EnsureHttpUrlReservation(string ipOrWildcard, int httpPort)
        {
            try
            {
                var url = $"http://{ipOrWildcard}:{httpPort}/";
                
                // 检查 URL 预留是否存在
                var process = new System.Diagnostics.Process
                {
                    StartInfo = new System.Diagnostics.ProcessStartInfo
                    {
                        FileName = "netsh",
                        Arguments = $"http show urlacl url={url}",
                        UseShellExecute = false,
                        RedirectStandardOutput = true,
                        RedirectStandardError = true,
                        CreateNoWindow = true
                    }
                };
                process.Start();
                var output = process.StandardOutput.ReadToEnd();
                process.WaitForExit();

                // 如果 URL 预留不存在，尝试添加
                if (!output.Contains(url))
                {
                    var displayName = ipOrWildcard == "+" ? "所有网卡" : ipOrWildcard;
                    Console.WriteLine($"  注册 HTTP URL 预留: {url} ({displayName})");
                    Console.WriteLine("  注意：这需要管理员权限。如果失败，请以管理员身份运行程序。");
                    
                    var addProcess = new System.Diagnostics.Process
                    {
                        StartInfo = new System.Diagnostics.ProcessStartInfo
                        {
                            FileName = "netsh",
                            Arguments = $"http add urlacl url={url} user=Everyone",
                            UseShellExecute = false,
                            RedirectStandardOutput = true,
                            RedirectStandardError = true,
                            CreateNoWindow = true,
                            Verb = "runas" // 请求管理员权限
                        }
                    };
                    try
                    {
                        addProcess.Start();
                        var addOutput = addProcess.StandardOutput.ReadToEnd();
                        var addError = addProcess.StandardError.ReadToEnd();
                        addProcess.WaitForExit();
                        
                        if (addProcess.ExitCode == 0)
                        {
                            Console.WriteLine($"  ✓ HTTP URL 预留已注册 ({displayName})");
                        }
                        else
                        {
                            Console.WriteLine($"  ⚠ 无法自动注册 HTTP URL 预留（可能需要管理员权限）");
                            Console.WriteLine($"  错误信息: {addError}");
                            Console.WriteLine($"  请手动运行（以管理员身份）:");
                            Console.WriteLine($"  netsh http add urlacl url={url} user=Everyone");
                            Console.WriteLine();
                            Console.WriteLine("  或者，以管理员身份运行此程序。");
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine($"  ⚠ 无法自动注册 HTTP URL 预留: {ex.Message}");
                        Console.WriteLine($"  请手动运行（以管理员身份）:");
                        Console.WriteLine($"  netsh http add urlacl url={url} user=Everyone");
                        Console.WriteLine();
                        Console.WriteLine("  或者，以管理员身份运行此程序。");
                    }
                }
                else
                {
                    var displayName = ipOrWildcard == "+" ? "所有网卡" : ipOrWildcard;
                    Console.WriteLine($"  ✓ HTTP URL 预留已存在 ({displayName})");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"  检查 HTTP URL 预留时发生错误: {ex.Message}");
                Console.WriteLine($"  如果程序无法启动 HTTP 服务，请以管理员身份运行。");
                Console.WriteLine();
            }
        }

        private static void EnsureFirewallRules(string localIp, int httpPort)
        {
            try
            {
                Console.WriteLine("检查防火墙规则...");
                
                // 检查UDP 3702规则
                var process = new System.Diagnostics.Process
                {
                    StartInfo = new System.Diagnostics.ProcessStartInfo
                    {
                        FileName = "netsh",
                        Arguments = "advfirewall firewall show rule name=\"WSD Test Service - Discovery\"",
                        UseShellExecute = false,
                        RedirectStandardOutput = true,
                        CreateNoWindow = true
                    }
                };
                process.Start();
                var output = process.StandardOutput.ReadToEnd();
                process.WaitForExit();

                if (!output.Contains("WSD Test Service - Discovery"))
                {
                    Console.WriteLine("  添加UDP 3702防火墙规则...");
                    var addProcess = new System.Diagnostics.Process
                    {
                        StartInfo = new System.Diagnostics.ProcessStartInfo
                        {
                            FileName = "netsh",
                            Arguments = "advfirewall firewall add rule name=\"WSD Test Service - Discovery\" dir=in action=allow protocol=UDP localport=3702",
                            UseShellExecute = false,
                            RedirectStandardOutput = true,
                            CreateNoWindow = true,
                            Verb = "runas" // 请求管理员权限
                        }
                    };
                    try
                    {
                        addProcess.Start();
                        addProcess.WaitForExit();
                        Console.WriteLine("  ✓ UDP 3702规则已添加");
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine($"  ⚠ 无法自动添加UDP 3702规则（可能需要管理员权限）: {ex.Message}");
                        Console.WriteLine($"  请手动运行: netsh advfirewall firewall add rule name=\"WSD Test Service - Discovery\" dir=in action=allow protocol=UDP localport=3702");
                    }
                }
                else
                {
                    Console.WriteLine("  ✓ UDP 3702规则已存在");
                }

                // 检查TCP HTTP端口规则
                process = new System.Diagnostics.Process
                {
                    StartInfo = new System.Diagnostics.ProcessStartInfo
                    {
                        FileName = "netsh",
                        Arguments = $"advfirewall firewall show rule name=\"WSD Test Service - Metadata\"",
                        UseShellExecute = false,
                        RedirectStandardOutput = true,
                        CreateNoWindow = true
                    }
                };
                process.Start();
                output = process.StandardOutput.ReadToEnd();
                process.WaitForExit();

                if (!output.Contains("WSD Test Service - Metadata"))
                {
                    Console.WriteLine($"  添加TCP {httpPort}防火墙规则...");
                    var addProcess = new System.Diagnostics.Process
                    {
                        StartInfo = new System.Diagnostics.ProcessStartInfo
                        {
                            FileName = "netsh",
                            Arguments = $"advfirewall firewall add rule name=\"WSD Test Service - Metadata\" dir=in action=allow protocol=TCP localport={httpPort}",
                            UseShellExecute = false,
                            RedirectStandardOutput = true,
                            CreateNoWindow = true,
                            Verb = "runas" // 请求管理员权限
                        }
                    };
                    try
                    {
                        addProcess.Start();
                        addProcess.WaitForExit();
                        Console.WriteLine($"  ✓ TCP {httpPort}规则已添加");
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine($"  ⚠ 无法自动添加TCP {httpPort}规则（可能需要管理员权限）: {ex.Message}");
                        Console.WriteLine($"  请手动运行: netsh advfirewall firewall add rule name=\"WSD Test Service - Metadata\" dir=in action=allow protocol=TCP localport={httpPort}");
                    }
                }
                else
                {
                    Console.WriteLine($"  ✓ TCP {httpPort}规则已存在");
                }
                Console.WriteLine();
            }
            catch (Exception ex)
            {
                Console.WriteLine($"  检查防火墙规则时发生错误: {ex.Message}");
                Console.WriteLine();
            }
        }

        private static void Cleanup()
        {
            try
            {
                _discoveryService?.Stop();
                _discoveryService?.Dispose();
            }
            catch { }

            try
            {
                _httpListener?.Stop();
                _httpListener?.Close();
            }
            catch { }

            try
            {
                _metadataService?.Dispose();
            }
            catch { }

            Console.WriteLine("服务已停止");
        }
    }
}

